package com.zhou.framework.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.zhou.framework.common.SpringFactory;
import com.zhou.framework.constant.AppEnum;
import com.zhou.framework.constant.CacheKeyEnum;
import com.zhou.util.*;
import com.zhou.framework.config.PasswordPolicyConfig;
import com.zhou.framework.config.SystemConfig;
import com.zhou.framework.exception.SessionOutTimeException;
import com.zhou.framework.exception.TokenException;
import com.zhou.framework.redis.util.RedisUtil;
import com.zhou.framework.jwt.model.LoginUser;
import com.zhou.org.dao.User;

import javax.servlet.http.HttpServletRequest;
import java.util.*;


/**
 * @author lang.zhou
 * @date 2022/5/5 16:36
 */
public class SessionUtil {

    private static RedisUtil redisUtil = SpringFactory.getBean(RedisUtil.class);

    private static String getCacheKey(String key){
        return CacheKeyEnum.LOGIN_USER_KEY + key;
    }
    public static void cacheUser(LoginUser user){
        int sessionOut = PasswordPolicyConfig.getInstance().getSessionOut();
        redisUtil.set(getCacheKey(user.getKey()) ,user,sessionOut * 60);
    }

    @SuppressWarnings("all")
    public static void clearCache(){
        Collection<String> keys = redisUtil.keys(CacheKeyEnum.LOGIN_USER_KEY + "*");
        redisUtil.redisTemplate.delete(keys);
    }

    public static LoginUser getCacheUser(String key){
        LoginUser user = redisUtil.get(getCacheKey(key));
        if(user == null){
            throw new SessionOutTimeException("会话失效");
        }
        return user;
    }

    public static String login(User user){
        String key = StringTool.uuid();
        String token = JWT.create().withAudience(key)
                //.withExpiresAt(date)
                .sign(Algorithm.HMAC256(user.getPassword()));
        LoginUser lu = new LoginUser(user);
        //活跃时间
        lu.setActiveTime(new Date().getTime());
        lu.setKey(key);

        HttpServletRequest request = WebUtil.currentRequest();
        if(request != null){
            lu.setIp(WebUtil.getIp(request));
            lu.setOs(WebUtil.getOsInfo(request));
            lu.setBrowser(WebUtil.getBrowserInfo(request));
            if(SystemConfig.getInstance().isLocation()){
                lu.setLocation(AddressUtil.getRealAddressByIP(lu.getIp()));
            }
        }
        cacheUser(lu);
        redisUtil.del(CacheKeyEnum.PASSWORD_ERROR_COUNT + "||" + user.getUsername());
        return token;
    }

    public static void logout(){
        LoginUser user = getCurrentUserSafe();
        if(user != null){
            logout(user.getKey());
        }
    }

    public static void logout(String key){
        String userKey = getCacheKey(key);
        redisUtil.del(userKey);
    }

    public static LoginUser getCurrentUser(){
        String s = getCurrentToken();
        Assert.notEmpty(s,"token为空");
        return decodeToken(s);
    }
    public static String getCurrentUserRealName(){
        LoginUser currentUser = getCurrentUser();
        return currentUser.getUser().getRealName();
    }
    public static Integer getCurrentOrgId(){
        LoginUser currentUser = getCurrentUser();
        return currentUser.getUser().getOrgId();
    }
    public static Integer getCurrentUserId(){
        LoginUser currentUser = getCurrentUser();
        return currentUser.getUserId();
    }
    public static LoginUser getCurrentUserSafe(){
        try{
            return getCurrentUser();
        }catch (Exception e){
            return null;
        }
    }
    public static boolean isLogin(){
        try{
            getCurrentUser();
            return true;
        }catch (Exception e){
            return false;
        }
    }
    public static LoginUser decodeToken(String token){
        String key;
        Assert.notEmpty(token,"token缺失");
        try {
            List<String> audience = JWT.decode(token).getAudience();
            key = audience.get(0);

        } catch (JWTDecodeException j) {
            throw new TokenException("token信息无效",j);
        }
        LoginUser u = getCacheUser(key);
        return u;
    }
    public static String getCurrentToken() {
        String token = null;
        HttpServletRequest request = WebUtil.currentRequest();
        if(request != null){
            token = request.getHeader(AppEnum.TOKEN_KEY);
        }
        return token;
    }
}
